# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 John Paulett (john -at- vanderbilt.edu)
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution.


"""File API for easily IO interactions. Handles interactions (reading and 
writing) Comma Separated Value files, :mod:`~pickle` files, etc.  The interactions
are designed so that a filename is passed in and all resource handling is 
handled within this module.

.. moduleauthor:: John Paulett <john.paulett -at- vanderbilt.edu>
"""

from __future__ import with_statement
import csv
import logging
import os
import pickle
import tempfile

logger = logging.getLogger(__name__)

def read_csv(filename):
    """Returns a generator with the data of the CSV file, specified by
    *filename* as a list of lists. Ignores empty lines.
    """
    with open(filename, 'rb') as f:
        reader = csv.reader(f)
        for line in reader:
            # prevent issues when the last line in the file is empty
            if len(line) > 0:
                yield line
                
def write_csv(filename, data, header=None):
    """Write a csv file to *filename*.  *data* should be a 2D list of the 
    data to write in the file.  If a *header* is specified, the header row
    is written to the file first.  The *header* should be a list of column
    names.
    """
    with open(filename, 'w') as f:
        writer = csv.writer(f, dialect=csv.excel)
        if header is not None:
            writer.writerow(header)
        writer.writerows(data)
        
def deserialize(filename):
    """Return the object or data structure in *filename*.
    """
    with open(filename, 'rb') as f:
        return pickle.load(f)

def serialize(filename, obj):
    """Persist the *obj* into a file specified by *filename*.
    """
    with open(filename, 'wb') as f:
        pickle.dump(obj, f)

def tmp_file(*args, **kw):
    """Creates a temporary file and returns the absolute pathname of the temp 
    file. The caller is responsible for removing once it is done with the file.
    Accepts all the  arguments of :func:`~tempfile.mkstemp`.
    """
    fd, fn = tempfile.mkstemp(**kw)
    os.close(fd)
    return fn

def tmp_dir(*args, **kw):
    """Creates a temporary directory and returns the absolute pathname to
    the new directory. The caller is responsible for removing the directory.
    Accepts all the arguments of :func:`~tempfile.mkdtemp`.
    """
    return tempfile.mkdtemp(**kw)

def list_dir(path):
    """Returns a list of all the files and directories in *path*.
    """
    return os.listdir(path)

def remove(path):
    """Deletes the file or directory specified by *path*. If it is a directory, 
    all sub-directories and files will be removed. Designed to be equivalent
    to the unix command :command:`rm -rf`
    
    .. warning::
        This method has not been extensively tested, especially on complex 
        situations such as relative paths, subdirectories, symlinks, and non-Linux 
        systems. Use at your own risk and make sure you have system backups.
    """
    if os.path.isfile(path) or os.path.islink(path):
        ## remove the file or link. catch links here to prevent directory
        ## symlinks from leading to over-deletion.
        os.remove(path)
    elif os.path.isdir(path):
        try:
            ## if the directory is empty, just delete it
            os.rmdir(path)
        except OSError:
            ## delete to sub files/directories
            for fn in os.listdir(path):
                remove(join(path, fn))
            ## delete the actual directory
            os.rmdir(path)
    else:
        ## should never occur, assuming the path is valid
        raise OSError, "%s is not a file or directory" % path               

def join(*args):
    """Alias of :func:`~os.path.join` that task a set of arguments and
    joins them using the approriate path separator.
    
    >>> join('dir', 'file.csv')
    'dir/file.csv'
    """
    return os.path.join(*args)


def get_dir(filename):
    """Get the absolute path to the directory in which *filename*
    exists.
    
    >>> get_dir(__file__)
    """
    return os.path.dirname(os.path.abspath(filename))
